/* 
 *  *  Written by Xing Jing */
/*
 * $Id: lsv.c $
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

#include "list.h"

#include "lsv_types.h"
#include "lsv_volume_proto.h"
#include "lsv_help.h"
#include "lsv_utils.h"
#include "lsv_conf.h"

lsv_s32_t __lsv_daemonize(int id) {
	int i, fd;
	
	//Enable core dump
    prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);

	if (fork() != 0)
		exit(0);

	if ((fd = open("/dev/tty", O_RDWR)) >= 0) { /* disassociate contolling tty */
		ioctl(fd, TIOCNOTTY, (char *) NULL);
		close(fd);
	}

	setpgrp();

	for (fd = 0; fd < 3; fd++)
		close(fd);

	i = open("/dev/null", O_RDONLY, 0);
	if (i != 0) {
		abort();
	}
	i = open("/dev/null", O_WRONLY, 0);
	if (i != 1) {
		abort();
	}

	{
		char *p;
		char prg_name[256];
		char log_name[1024];
		char hostname[256];

		strcpy(prg_name, getenv("_"));
		i = strlen(prg_name);
		while (*(prg_name + i) != '/')
			i--;
		i++;
		p = &(prg_name[i]);

		gethostname(hostname, 256);

		sprintf(log_name, "%s%s-%d.%s.log",
		LSV_LOG_FILE_PATH, p, id, hostname);
		unlink(log_name);

		i = open(log_name, (O_WRONLY | O_CREAT), 0666);
		if (i != 2) {
			abort();
		}
	}
	/*
	 */
	setpriority(PRIO_PGRP, getpgrp(), -20);

	return 0;
}

lsv_s32_t lsv_volumep_create(lsv_ino_t ino, lsv_u64_t size, lsv_volume_proto_t **volume_proto) {
	lsv_s32_t rc = 0;
	lsv_volume_proto_t *tmp = NULL;

	tmp = (lsv_volume_proto_t *) malloc(sizeof(lsv_volume_proto_t));
	if (tmp == NULL) {
		rc = -ENOMEM;
		return rc;
	}

	bzero(tmp, sizeof(lsv_volume_proto_t));

	tmp->ino = ino;
	tmp->size = size;
	tmp->u.log_page_id = 1;
	tmp->u.volume_page_id = 2;
	tmp->u.rcache_page_id = 3;
	tmp->u.wbuf_page_id = 7;
	tmp->u.system_power_on = 0;

	list_add_tail(&(tmp->vp_list), &lsv_volume_proto_head);

	(*volume_proto) = tmp;

	return rc;
}

lsv_s32_t lsv_volumep_lookup(lsv_ino_t ino, lsv_volume_proto_t **volume_proto) {
	lsv_s32_t rc = -ENOENT;
	struct list_head *index = NULL, *head = NULL;
	lsv_volume_proto_t *tmp = NULL;

	head = &lsv_volume_proto_head;

	list_for_each(index, head)
	{
		//tmp = list_entry(index, lsv_volume_proto_t, vp_list);
		tmp = (lsv_volume_proto_t *) index;
		if (tmp->ino == ino) {
			*volume_proto = tmp;
			rc = 0;
			break;
		}
	}
	return rc;
}

lsv_s32_t lsv_volumep_load(lsv_ino_t ino, lsv_volume_proto_t **volume_proto) {
	lsv_s32_t rc = 0;
	lsv_s32_t fd = 0;
	lsv_volume_proto_t *tmp = NULL;
	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s%d", LSV_VOLUME_STORAGE_FILE_PREFIX, ino);

	tmp = (lsv_volume_proto_t *) malloc(sizeof(lsv_volume_proto_t));
	if (tmp == NULL) {
		rc = -ENOMEM;
		return rc;
	}

	bzero(tmp, sizeof(lsv_volume_proto_t));

	tmp->ino = ino;
	/*Load volume chunk 0 page 0 to fill volume_proto->u*/
	fd = open(path_name, O_RDONLY);
	if (fd >= 0) {
		DINFO("fd %d\n", fd);
		rc = read(fd, &(tmp->u), sizeof(tmp->u));
		if (rc < 0) {
			DINFO("read %s fail\n", path_name);
			free(tmp);
			close(fd);
			return -errno;
		}
		close(fd);
	} else {
		DINFO("open %s fail\n", path_name);
		free(tmp);
		return -errno;
	}

	list_add_tail(&(tmp->vp_list), &lsv_volume_proto_head);

	(*volume_proto) = tmp;
	DINFO("bitmap_chunk_id:%u %s\n", tmp->u.bitmap_chunk_id, path_name);

	return rc;
}


lsv_s32_t lsv_volumep_dump(lsv_volume_proto_t *volume_proto) {
	lsv_s32_t rc = 0;
	lsv_s32_t fd = 0;
	lsv_ino_t ino;
	lsv_volume_proto_t *tmp = NULL;
	char path_name[LSV_MAX_STRING_LEN];

	ino = volume_proto->ino;
	sprintf(path_name, "%s%d", LSV_VOLUME_STORAGE_FILE_PREFIX, ino);
	DINFO("bitmap_chunk_id:%u %s\n", volume_proto->u.bitmap_chunk_id, path_name);

	/*Dump volume_proto->u to volume chunk 0 page 0*/
	fd = open(path_name, O_WRONLY);
	if (fd >= 0) {
		DINFO("fd %d\n", fd);
		rc = write(fd, &(volume_proto->u), sizeof(volume_proto->u));
		if (rc < 0) {
			DINFO("write %s fail\n", path_name);
			close(fd);
			return -errno;
		}
		close(fd);
	} else {
		DINFO("open %s fail,errno:%d\n", path_name, errno);
		return -errno;
	}

	DINFO("write %s %d\n", path_name, rc);
	return rc;
}
/*This is end of lsv_utils.c*/
